#!/usr/bin/env bash
#version 0.962-N/HS

#You may share this script on the condition all references to RaspberryConnect.com
#must be included in copies or derivatives of this script.

#A script to switch between a wifi network and a non internet routed Hotspot
#Works at startup or with a seperate timer or manually without a reboot
#Other setup required find out more at
#http://www.raspberryconnect.com

#Additions where made for the Phoniebox project
#https://github.com/MiczFlor/RPi-Jukebox-RFID

while getopts "a" opt; do
    case $opt in
        a )
            FORCE_HOTSPOT=true
            ;;
        * )
            echo "option not valid"
            exit
            ;;
    esac
done

NO_SSID='NoSSid'
ssidChk="$NO_SSID"

wifidev="%WIFI_INTERFACE%" #device name to use.
#use the command: iw dev ,to see wifi interface name
hotspot_ip=%AUTOHOTSPOT_IP%
daemon_service="%AUTOHOTSPOT_SERVICE_DAEMON%"

IFSdef=$IFS
cnt=0
#These four lines capture the wifi networks the RPi is setup to use
wpassid=$(awk '/ssid="/{ print $0 }' /etc/wpa_supplicant/wpa_supplicant.conf | awk -F'ssid=' '{ print $2 }' | sed 's/\r//g'| awk 'BEGIN{ORS=","} {print}' | sed 's/\"/''/g' | sed 's/,$//')
IFS=","
ssids=($wpassid)
IFS=$IFSdef #reset back to defaults


#Note:If you only want to check for certain SSIDs
#Remove the # in in front of ssids=('mySSID1'.... below and put a # infront of all four lines above
# separated by a space, eg ('mySSID1' 'mySSID2')
#ssids=('mySSID1' 'mySSID2' 'mySSID3')

#Enter the Routers Mac Addresses for hidden SSIDs, seperated by spaces ie
#( '11:22:33:44:55:66' 'aa:bb:cc:dd:ee:ff' )
mac=()

ssidsmac=("${ssids[@]}" "${mac[@]}") #combines ssid and MAC for checking

CreateAdHocNetwork()
{
    echo "Creating Hotspot"
    ip link set dev "$wifidev" down
    ip a add "$hotspot_ip"/24 brd + dev "$wifidev"
    ip link set dev "$wifidev" up
    dhcpcd -k "$wifidev" >/dev/null 2>&1
    systemctl start dnsmasq
    systemctl start hostapd
}

KillHotspot()
{
    echo "Shutting Down Hotspot"
    ip link set dev "$wifidev" down
    systemctl stop hostapd
    systemctl stop dnsmasq
    ip addr flush dev "$wifidev"
    ip link set dev "$wifidev" up
    dhcpcd  -n "$wifidev" >/dev/null 2>&1
}

CheckWifiUp()
{
    echo "Checking WiFi connection ok"
    sleep 20 #give time for connection to be completed to router
    if ! wpa_cli -i "$wifidev" status | grep 'ip_address' >/dev/null 2>&1
    then #Failed to connect to wifi (check your wifi settings, password etc)
        echo 'Wifi failed to connect, falling back to Hotspot.'
        wpa_cli terminate "$wifidev" >/dev/null 2>&1
        CreateAdHocNetwork
    fi
}

InitWPA() {
    systemctl restart "$daemon_service"
}

CheckServices()
{
    #After some system updates hostapd gets masked using Raspbian Buster, and above. This checks and fixes
    #the issue and also checks dnsmasq is ok so the hotspot can be generated.
    #Check Hostapd is unmasked and disabled
    if (systemctl -all list-unit-files hostapd.service | grep "hostapd.service masked") >/dev/null 2>&1 ;then
        systemctl unmask hostapd.service >/dev/null 2>&1
    fi
    if (systemctl -all list-unit-files hostapd.service | grep "hostapd.service enabled") >/dev/null 2>&1 ;then
        systemctl disable hostapd.service >/dev/null 2>&1
        systemctl stop hostapd >/dev/null 2>&1
    fi
    #Check dnsmasq is disabled
    if (systemctl -all list-unit-files dnsmasq.service | grep "dnsmasq.service masked") >/dev/null 2>&1 ;then
        systemctl unmask dnsmasq >/dev/null 2>&1
    fi
    if (systemctl -all list-unit-files dnsmasq.service | grep "dnsmasq.service enabled") >/dev/null 2>&1 ;then
        systemctl disable dnsmasq >/dev/null 2>&1
        systemctl stop dnsmasq >/dev/null 2>&1
    fi
}

CheckDevice()
{
    echo "Device availability check"
    local j=0
    while [ true ] #wait for wifi if busy, usb wifi is slower.
    do

        if [ $j -ge 5 ]; then
            #if no wifi device,ie usb wifi removed, activate wifi so when it is
            #reconnected wifi to a router will be available
            echo "No wifi device '$wifidev' connected"
            InitWPA
            exit 1
        elif (iw dev "$wifidev" info 2>&1 >/dev/null) ; then
            echo "Wifi device '$wifidev' available"
            if (rfkill list wifi -rno HARD,SOFT | grep -i "unblocked.*unblocked") >/dev/null 2>&1 ; then
                local wifidev_up=$(ip link show "$wifidev" up)
                if [ -z "$wifidev_up" ]; then
                    echo "Wifi is down. Setting up"
                    ip link set dev "$wifidev" up
                    sleep 2
                fi
                return
            else
                echo "Wifi is deactivated"
                exit 0
            fi
        else
            j=$((j + 1))
            sleep 2
        fi
    done
}

FindSSID()
{
    if [ -n "$FORCE_HOTSPOT" ]; then return; fi

    #Check to see what SSID's and MAC addresses are in range
    echo "SSID availability check"
    local i=0; j=0
    while [ $i -eq 0 ]
    do
        scanreply=$(iw dev "$wifidev" scan ap-force 2>&1)
        ssidreply=$(echo "$scanreply" | egrep "^BSS|SSID:")
        if [ $j -ge 5 ]; then
            ssidreply=""
            i=1
        elif [ -z "$ssidreply" ] ; then
            echo "Error scan SSID's, try $j: $scanreply"
            j=$((j + 1))
            sleep 2
        else
            #success
            i=1
        fi
    done

    for ssid in "${ssidsmac[@]}"
    do
        if (echo "$ssidreply" | grep "$ssid") >/dev/null 2>&1
        then
            echo "Valid SSID detected, assessing Wifi status"
            ssidChk=$ssid
            break
        fi
    done

    if [ "$ssidChk" == "$NO_SSID" ]; then
        echo "No Valid SSID detected"
    fi
}

CheckSSID()
{
    #Create Hotspot or connect to valid wifi networks
    if [ "$ssidChk" != "$NO_SSID" ]
    then
        if systemctl status hostapd | grep "(running)" >/dev/null 2>&1
        then #hotspot running and ssid in range
            KillHotspot
            echo "Hotspot Deactivated, Bringing Wifi Up"
            InitWPA
            CheckWifiUp
        elif { wpa_cli -i "$wifidev" status | grep 'ip_address'; } >/dev/null 2>&1
        then #Already connected
            echo "Wifi already connected to a network"
        else #ssid exists and no hotspot running connect to wifi network
            echo "Connecting to the WiFi Network"
            InitWPA
            CheckWifiUp
        fi
    else #ssid or MAC address not in range
        if systemctl status hostapd | grep "(running)" >/dev/null 2>&1
        then
            echo "Hostspot already active"
        elif { wpa_cli status | grep "$wifidev"; } >/dev/null 2>&1
        then
            echo "Cleaning wifi files and Activating Hotspot"
            wpa_cli terminate >/dev/null 2>&1
            ip addr flush "$wifidev"
            ip link set dev "$wifidev" down
            rm -r /var/run/wpa_supplicant >/dev/null 2>&1
            CreateAdHocNetwork
        else #"No SSID, activating Hotspot"
            CreateAdHocNetwork
        fi
    fi
}

CheckServices
CheckDevice
FindSSID
CheckSSID
